﻿using System;
using Marvin.Optimization;
using MathNet.Numerics.LinearAlgebra.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Marvin.Tests.Optimization.GradientDescentTests
{
    /// <summary>
    /// Summary description for LinearOptimization
    /// </summary>
    [TestClass]
    public class LinearOptimization
    {
        private class ParabolaDerivative : IGradientFunction
        {
            #region Implementation of IGradientFunction

            public ParabolaDerivative(int dimensions)
            {
                _dimensions = dimensions; 
            }

            private int _dimensions; 
            public Vector<double> Calculate(Vector<double> x)
            {
                
                return x.Subtract(1.0).Multiply(2.0); 
            }

            public int GetDimension()
            {
                return _dimensions; 
            }

            #endregion
        }

        private static bool IsEqualByPrecision(double[] a, double[] b, double precision)
        {
            if (a.Length != b.Length)
                return false; 
           
            for (int dimension = 0; dimension < a.Length; dimension++)
            {
                if (Math.Abs(a[dimension] - b[dimension]) > precision)
                    return false; 
            }
            return true; 
        }

        [TestMethod]
        public void GradientDescentFindsTheMinimumOfaParabola()
        {
            IGradientFunction parabola = new ParabolaDerivative(3);

            var gradientDescent = new GradientDescent(parabola)
                {
                    Precision = 0.00001
                };
            var minimum = gradientDescent.CalculateMinimum();
            var expected = new[] {1.0, 1.0, 1.0};
            var resultIsEqualToExpectedResult = IsEqualByPrecision(expected, minimum.ToArray(), 0.01);
            Assert.IsTrue(resultIsEqualToExpectedResult);
        }
    }
}
